defmodule Coffer.Transformation do
  def transform(version, definition, file) do
    transform(version, definition, file, definition.transform(version, file))
  end

  defp transform(version, definition, file, :noaction) do
    file = ensure_storage_path(version, definition, file)
    case File.cp(file.original_path, file.storage_path) do
      :ok -> {:ok, file}
      {:error, error} -> {:error, %Coffer.File{file | error: error}}
    end
  end

  defp transform(version, definition, file, func) when is_function(func, 2) do
    file = ensure_storage_path(version, definition, file)
    {command, args} = func.(file.original_path, file.storage_path)
    case System.cmd(command, args, stderr_to_stdout: true) do
      {_, 0} -> {:ok, file}
      {error, _} -> {:error, %Coffer.File{file | error: error}}
    end
  end

  defp ensure_storage_path(version, definition, file) do
    storage_path = build_storage_path(version, definition, file)
    %Coffer.File{file | storage_path: storage_path, version: version}
  end

  defp build_storage_path(version, definition, file) do
    filename = definition.filename(version, file)
    storage_dir = definition.storage_dir(version, file)
    File.mkdir_p!(storage_dir)
    Path.join(storage_dir, filename)
  end
end